home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CD ROM Paradise Collection 4
/
CD ROM Paradise Collection 4 1995 Nov.iso
/
asm
/
cpu_id.zip
/
CPUID3.ASM
next >
Wrap
Assembly Source File
|
1994-01-04
|
18KB
|
543 lines
; Filename: cpuid32.msm
;
; This program has been developed by Intel Corporation. You have
; Intel's permission to incorporate this source code into your
; product royalty free.
;
; Intel specifically disclaims all warranties, express or implied,
; and all liability, including consequential and other indirect
; damages, for the use of this code, including liability for
; infringement of any proprietary rights. Intel does not assume
; any responsibility for any errors which may appear in this code
; nor any responsibility to update it.
;
; This program contains three parts:
; Part 1: Identifies CPU type in the variable cpu_type:
; 0=8086 processor
; 2=Intel 286 processor
; 3=Intel386(TM) processor
; 4=Intel486(TM) processor
; 5=Pentium(TM) processor
;
; Part 2: Identifies FPU type in the variable fpu_type:
; 0=FPU not present
; 1=FPU present
; 2=287 present (only if cpu_type=3)
; 3=387 present (only if cpu_type=3)
;
; Part 3: Prints out the appropriate message. This part can
; be removed if this program is not used in a DOS-based
; system. Portions affected are at the end of the
; data segment and the print procedure in the code
; segment.
;
; REVISION HISTORY:
; Date: 4/93
; 1. Replaced the .486 with .186 to avoid generation of 0FH type long
; conditional branches (such as the branch to end_get_cpuid at
; the end of the 8086/8088 test, near code address 003D). These
; are not executable on the 8086/8088 and 80286, so the code falls
; into some strange place and hangs the system. The .186 also allows
; multi-bit shifts to unpack CPUID info. Using .186 requires
; that all 32-bit operand prefix (66H) be inserted by hand.
; This is done with a macro (OPND32).
; 2. Avoid all usage of 32-bit operands until it is clear that the
; CPU is at least an 80386. The use of the Exx registers caused
; the generation of the 66H prefix, which are not executed
; correctly on the 8086/8088 and 80286.
; 3. Eliminated all the register save/restore and added comment
; that all registers are used by the functions.
; 4. Do the stack alignment just before messing with the AC bit in
; EFLAGS, otherwise the stack may not be properly aligned. Also
; restore the AC bit immediately, so it does not stay set.
; 5. Changed the FPU detection to set one flag fpu_type (instead of
; the previous two flags: fpu_present and infinity). An fpu_type
; of zero indicates no floating point unit is present, an fpu_type
; of 2 indicates an 80287 is present, an fpu_type of 3 indicates
; an 80387 is present.
;
; If this code is assembled with MASM with no options specified, it
; runs correctly on an 8086/8088, 80286, 80386, 80486, and
; Pentium(tm) processor.
;
TITLE CPUID
DOSSEG
.model small
.stack 100h
.186
OPND32 MACRO op_code, op_erand
db 66h ; Force 32-bit operand size
IFNB <op_code>
db op_code
IFNB <op_erand>
dd op_erand; 32-bit immediate value
ENDIF
ENDIF
ENDM
CPUID MACRO
db 0fh ; Hardcoded opcode for CPUID instruction
db 0a2h
ENDM
TRUE equ 1
FAMILY_MASK equ 0f00h
FAMILY_SHIFT equ 8
MODEL_MASK equ 0f0h
MODEL_SHIFT equ 4
STEPPING_MASK equ 0fh
FPU_FLAG equ 1h
MCE_FLAG equ 80h
CMPXCHG8B_FLAG equ 100h
.data
fp_status dw ?
vendor_id db 12 dup (?)
cpu_type db ?
modell db ?
stepping db ?
id_flag db 0
fpu_type db 0
intel_proc db 0
feature_flags dw 2 dup (0)
;
; remove the remaining data declarations if not using the DOS-based
; print procedure
;
id_msg db "This system has a$"
fp_8087 db " and an 8087 math coprocessor$"
fp_80287 db " and an 80287 math coprocessor$"
fp_80387 db " and an 80387 math coprocessor$"
c8086 db "n 8086/8088 processor$"
c286 db "n 80286 processor$"
c386 db "n 80386 processor$"
c486 db "n 80486 DX processor or 80487 SX math coprocessor$"
c486nfp db "n 80486 SX processor$"
Intel486_msg db 13,10,"This system contains a Genuine Intel486(TM) processor",13,10,"$"
Pentium_msg db 13,10,"This system contains a Genuine Intel Pentium(TM) processor",13,10,"$"
modelmsg db "Model: $"
steppingmsg db "Stepping: $"
familymsg db 13,10,"Processor Family: $"
period db ".",13,10,"$"
dataCR db ?,13,10,"$"
intel_id db "GenuineIntel"
fpu_msg db 13,10,"This processor contains a FPU",13,10,"$"
mce_msg db "This processor supports the Machine Check Exception",13,10,"$"
cmp_msg db "This processor supports the CMPXCHG8B instruction",13,10,"$"
not_intel db "t least an 80486 processor.",13,10
db "It does not contain a Genuine Intel part and as a result,",13,10
db "the CPUID detection information cannot be determined at this time.",13,10,"$"
;
; The purpose of this code is to identify the processor and
; coprocessor that is currently in the system. The program first
; determines the processor id. When that is accomplished,
; the program then determines whether a coprocessor
; exists in the system. If a coprocessor or integrated
; coprocessor exists, the program identifies
; the coprocessor id. The program then prints out
; the CPU and floating point presence and type.
;
.code
start: mov ax, @data
mov ds, ax ; set segment register
mov es, ax ; set segment register
pushf ; save for restoration at end
call get_cpuid
call get_fpuid
call print
popf
mov ax, 4c00h ; terminate program
int 21h
get_cpuid proc
;
; This procedure determines the type of CPU in a system
; and sets the cpu_type variable with the appropriate
; value.
; All registers are used by this procedure, none are preserved.
; Intel 8086 CPU check
; Bits 12-15 of the FLAGS register are always set on the
; 8086 processor.
;
check_8086:
pushf ; push original FLAGS
pop ax ; get original FLAGS
mov cx, ax ; save original FLAGS
and ax, 0fffh ; clear bits 12-15 in FLAGS
push ax ; save new FLAGS value on stack
popf ; replace current FLAGS value
pushf ; get new FLAGS
pop ax ; store new FLAGS in AX
and ax, 0f000h ; if bits 12-15 are set, then CPU
cmp ax, 0f000h ; is an 8086/8088
mov cpu_type, 0 ; turn on 8086/8088 flag
jne check_80286 ; jump if CPU is not 8086/8088
jmp end_get_cpuid
; Intel 286 CPU check
; Bits 12-15 of the FLAGS register are always clear on the
; Intel 286 processor in real-address mode.
;
check_80286:
or cx, 0f000h ; try to set bits 12-15
push cx ; save new FLAGS value on stack
popf ; replace current FLAGS value
pushf ; get new FLAGS
pop ax ; store new FLAGS in AX
and ax, 0f000h ; if bits 12-15 clear, CPU=80286
mov cpu_type, 2 ; turn on 80286 flag
jnz check_80386 ; if no bits set, CPU is 80286
jmp end_get_cpuid
; Intel386 CPU check
; The AC bit, bit #18, is a new bit introduced in the EFLAGS
; register on the Intel486 DX CPU to generate alignment faults.
; This bit cannot be set on the Intel386 CPU.
;
check_80386:
; It is now safe to use 32-bit opcode/operands
mov bx, sp ; save current stack pointer to align
and sp, not 3 ; align stack to avoid AC fault
OPND32
pushf ; push original EFLAGS
OPND32
pop ax ; get original EFLAGS
OPND32
mov cx, ax ; save original EFLAGS
OPND32 35h, 40000h ; flip AC bit in EFLAGS
OPND32
push ax ; save new EFLAGS value on stack
OPND32
popf ; replace current EFLAGS value
OPND32
pushf ; get new EFLAGS
OPND32
pop ax ; store new EFLAGS in EAX
OPND32
xor ax, cx ; can't toggle AC bit, CPU=80386
mov cpu_type, 3 ; turn on 80386 CPU flag
mov sp, bx ; restore original stack pointer
jz end_get_cpuid ; jump if 80386 CPU
and sp, not 3 ; align stack to avoid AC fault
OPND32
push cx
OPND32
popf ; restore AC bit in EFLAGS first
mov sp, bx ; restore original stack pointer
; Intel486 DX CPU, Intel487 SX NDP, and Intel486 SX CPU check
; Checking for ability to set/clear ID flag (Bit 21) in EFLAGS
; which indicates the presence of a processor
; with the ability to use the CPUID instruction.
;
check_80486:
mov cpu_type, 4 ; turn on 80486 CPU flag
OPND32
mov ax, cx ; get original EFLAGS
OPND32 35h, 200000h ; flip ID bit in EFLAGS
OPND32
push ax ; save new EFLAGS value on stack
OPND32
popf ; replace current EFLAGS value
OPND32
pushf ; get new EFLAGS
OPND32
pop ax ; store new EFLAGS in EAX
OPND32
xor ax, cx ; can't toggle ID bit,
je end_get_cpuid ; CPU=80486
; Execute CPUID instruction to determine vendor, family,
; model and stepping.
;
check_vendor:
mov id_flag, 1 ; set flag indicating use of CPUID inst.
OPND32
xor ax, ax ; set up input for CPUID instruction
CPUID ; macro for CPUID instruction
OPND32
mov word ptr vendor_id, bx ; setup to test for vendor id
OPND32
mov word ptr vendor_id[+4], dx
OPND32
mov word ptr vendor_id[+8], cx
mov si, offset vendor_id
mov di, offset intel_id
mov cx, length intel_id
compare:
repe cmpsb ; compare vendor id to "GenuineIntel"
or cx, cx
jnz end_get_cpuid ; if not zero, not an Intel CPU,
intel_processor:
mov intel_proc, 1
cpuid_data:
OPND32
cmp ax, 1 ; make sure 1 is a valid input
; value for CPUID
jl end_get_cpuid ; if not, jump to end
OPND32
xor ax, ax ; otherwise, use as input to CPUID
OPND32
inc ax ; and get stepping, model and family
CPUID
mov stepping, al
and stepping, STEPPING_MASK ; isolate stepping info
and al, MODEL_MASK ; isolate model info
shr al, MODEL_SHIFT
mov modell, al
and ax, FAMILY_MASK ; mask everything but family
shr ax, FAMILY_SHIFT
mov cpu_type, al ; set cpu_type with family
OPND32
mov feature_flags, dx ; save feature flag data
end_get_cpuid:
ret
get_cpuid endp
;******************************************************************
get_fpuid proc
;
; This procedure determines the type of FPU in a system
; and sets the fpu_type variable with the appropriate
; value.
; All registers are used by this procedure, none are preserved.
; Coprocessor check
; The algorithm is to determine whether the floating-point
; status and control words can be written to. If not, no
; coprocessor exists. If the status and control words can be
; written to, the correct coprocessor is then determined
; depending on the processor id. The Intel386 CPU can
; work with either an Intel287 NDP or an Intel387 NDP.
; The infinity of the coprocessor must be
; checked to determine the correct coprocessor id.
fninit ; reset FP status word
mov fp_status, 5a5ah; initialize temp word to
; non-zero value
fnstsw fp_status ; save FP status word
mov ax, fp_status ; check FP status word
cmp al, 0 ; see if correct status with
; written
mov fpu_type, 0 ; no fpu present
jne end_get_fpuid
check_control_word:
fnstcw fp_status ; save FP control word
mov ax, fp_status ; check FP control word
and ax, 103fh ; see if selected parts
; looks OK
cmp ax, 3fh ; check that 1's & 0's
; correctly read
mov fpu_type, 0
jne end_get_fpuid
mov fpu_type, 1
;
; 80287/80387 check for the Intel386 CPU
;
check_infinity:
cmp cpu_type, 3
jne end_get_fpuid
fld1 ; must use default control from FNINIT
fldz ; form infinity
fdiv ; 8087 and Intel287 NDP say +inf = -inf
fld st ; form negative infinity
fchs ; Intel387 NDP says +inf <> -inf
fcompp ; see if they are the same and remove them
fstsw fp_status ; look at status from FCOMPP
mov ax, fp_status
mov fpu_type, 2 ; store Intel287 NDP for fpu type
sahf ; see if infinities matched
jz end_get_fpuid ; jump if 8087 or Intel287 is present
mov fpu_type, 3 ; store Intel387 NDP for fpu type
end_get_fpuid:
ret
get_fpuid endp
;*********************************************************************
print proc
;
; This procedure prints the appropriate cpuid string and
; numeric processor presence status. If the CPUID instruction
; was supported, this procedure prints out cpuid info.
; All registers are used by this procedure, none are preserved.
cmp id_flag, 1 ; if set to 1, cpu supports
; CPUID instruction
; print detailed CPUID information
jne cont
jmp print_cpuid_data
cont: mov dx, offset id_msg ; print initial message
mov ah, 9h
int 21h
print_86:
cmp cpu_type, 0
jne print_286
mov dx, offset c8086
mov ah, 9h
int 21h
cmp fpu_type, 0
jne cont2
jmp end_print
cont2: mov dx, offset fp_8087
mov ah, 9h
int 21h
jmp end_print
print_286:
cmp cpu_type, 2
jne print_386
mov dx, offset c286
mov ah, 9h
int 21h
cmp fpu_type, 0
jne cont3
jmp end_print
cont3: mov dx, offset fp_80287
mov ah, 9h
int 21h
jmp end_print
print_386:
cmp cpu_type, 3
jne print_486
mov dx, offset c386
mov ah, 9h
int 21h
cmp fpu_type, 0
jne cont4
jmp end_print
cont4: cmp fpu_type, 2
jne print_387
mov dx, offset fp_80287
mov ah, 9h
int 21h
jmp end_print
print_387:
mov dx, offset fp_80387
mov ah, 9h
int 21h
jmp end_print
print_486:
cmp fpu_type, 0
je print_Intel486sx
mov dx, offset c486
mov ah, 9h
int 21h
jmp end_print
print_Intel486sx:
mov dx, offset c486nfp
mov ah, 9h
int 21h
jmp end_print
print_cpuid_data:
cmp_vendor:
cmp intel_proc, 1
je cont5
jmp not_GenuineIntel
cont5: cmp cpu_type, 4 ; if cpu_type=4, print
; Intel486 CPU message
jne check_Pentium
mov dx, offset Intel486_msg
mov ah, 9h
int 21h
jmp print_family
check_Pentium:
cmp cpu_type, 5 ; if cpu_type=5, print
jne print_features ; Pentium processor message
mov dx, offset Pentium_msg
mov ah, 9h
int 21h
print_family:
mov dx, offset familymsg ; print family msg
mov ah, 9h
int 21h
mov al, cpu_type
mov byte ptr dataCR, al
add byte ptr dataCR, 30h ; convert to ASCII
mov dx, offset dataCR ; print family info
mov ah, 9h
int 21h
print_model:
mov dx, offset modelmsg ; print model msg
mov ah, 9h
int 21h
mov al, modell
mov byte ptr dataCR, al
add byte ptr dataCR, 30h ; convert to ASCII
mov dx, offset dataCR ; print model info
mov ah, 9h
int 21h
print_stepping:
mov dx, offset steppingmsg ; print stepping msg
mov ah, 9h
int 21h
mov al, stepping
mov byte ptr dataCR, al
add byte ptr dataCR, 30h ; convert to ASCII
mov dx, offset dataCR ; print stepping info
mov ah, 9h
int 21h
print_features:
mov ax, feature_flags
and ax, FPU_FLAG ; check for FPU
jz check_MCE
mov dx, offset fpu_msg
mov ah, 9h
int 21h
check_MCE:
mov ax, feature_flags
and ax, MCE_FLAG ; check for MCE
jz check_CMPXCHG8B
mov dx, offset mce_msg
mov ah, 9h
int 21h
check_CMPXCHG8B:
mov ax, feature_flags
and ax, CMPXCHG8B_FLAG ; check for CMPXCHG8B
jz end_print
mov dx, offset cmp_msg
mov ah, 9h
int 21h
jmp end_print
not_GenuineIntel:
mov dx, offset not_Intel
mov ah, 9h
int 21h
end_print:
ret
print endp
end start